package incremental

import (
	"fmt"
	"reflect"

	"gorm.io/gorm"
)

// ChangeType 变更类型
type ChangeType string

// 变更类型常量
const (
	ChangeInsert ChangeType = "INSERT"
	ChangeUpdate ChangeType = "UPDATE"
	ChangeDelete ChangeType = "DELETE"
)

// Change 数据变更记录
type Change struct {
	ModelName string                 `json:"model_name"`
	TableName string                 `json:"table_name"`
	RecordID  interface{}            `json:"record_id"`
	Type      ChangeType             `json:"type"`
	OldValues map[string]interface{} `json:"old_values,omitempty"`
	NewValues map[string]interface{} `json:"new_values,omitempty"`
}

type ChangeHandler struct {
	db        *gorm.DB        // 数据库连接实例
	computer  *Computer       // 增量计算器
	processor *BatchProcessor // 批量处理器
}

// NewChangeHandler 创建变更处理器
func NewChangeHandler(db *gorm.DB, computer *Computer, processor *BatchProcessor) *ChangeHandler {

	changeHandler := ChangeHandler{
		db:        db,
		computer:  computer,
		processor: processor,
	}
	changeHandler.registerCallbacks()
	return &changeHandler
}

// registerCallbacks 注册数据库回调函数以触发增量计算
func (c *ChangeHandler) registerCallbacks() error {
	// 注册创建操作后的回调
	c.db.Callback().Create().After("gorm:create").Register("incremental:create:after", c.HandleAfterCreate)

	// 注册更新操作前的回调
	c.db.Callback().Update().Before("gorm:update").Register("incremental:update:before", c.HandleBeforeUpdate)

	// 注册删除操作后的回调
	c.db.Callback().Delete().After("gorm:delete").Register("incremental:delete:after", c.HandleAfterDelete)

	return nil
}

// HandleAfterCreate 处理创建操作后的增量计算并收集变更
func (c *ChangeHandler) HandleAfterCreate(tx *gorm.DB) {

	if tx.Statement != nil && tx.Statement.Model != nil {
		// 获取表名
		tableName := tx.Statement.Table
		if tableName == "" {
			return
		}

		// 获取模型名（这里简化处理，实际应该从Schema中获取）
		modelName := reflect.TypeOf(tx.Statement.Model).Elem().Name()

		// 创建变更记录
		change := &Change{
			ModelName: modelName,
			TableName: tableName,
			Type:      ChangeInsert,
			NewValues: make(map[string]interface{}),
		}

		// 提取变更字段
		if tx.Statement.Schema != nil {
			for _, field := range tx.Statement.Schema.Fields {
				if field.DBName != "" {
					// 从模型中获取字段值
					fieldValue := field.ReflectValueOf(tx.Statement.Context, tx.Statement.ReflectValue)
					if fieldValue.IsValid() && fieldValue.CanInterface() {
						change.NewValues[field.DBName] = fieldValue.Interface()

						// 如果是主键字段，设置记录ID
						if field.PrimaryKey {
							change.RecordID = fieldValue.Interface()
						}
					}
				}
			}
		}

		// 检查是否在事务中
		_, isInTransaction := tx.Statement.ConnPool.(interface{ Commit() error })

		if isInTransaction {
			// 在事务中，使用异步模式不进行wait
			err := c.processor.AddChange(change)
			if err != nil {
				fmt.Printf("处理变更时出错: %v\n", err)
			}
		} else {
			// 不在事务中，使用同步模式进行wait
			err := c.processor.AddChange(change)
			if err != nil {
				fmt.Printf("处理变更时出错: %v\n", err)
			}
			// 等待处理完成
			c.processor.Wait()
		}
	}
}

// HandleAfterDelete 处理删除操作后的增量计算并收集变更
func (c *ChangeHandler) HandleAfterDelete(tx *gorm.DB) {

	if tx.Statement != nil && tx.Statement.Model != nil {
		// 获取表名
		tableName := tx.Statement.Table
		if tableName == "" {
			return
		}

		// 获取模型名
		modelName := reflect.TypeOf(tx.Statement.Model).Elem().Name()

		// 创建变更记录
		change := &Change{
			ModelName: modelName,
			TableName: tableName,
			Type:      ChangeDelete,
			OldValues: make(map[string]interface{}),
		}

		// 提取变更字段
		if tx.Statement.Schema != nil {
			for _, field := range tx.Statement.Schema.Fields {
				if field.DBName != "" {
					// 从模型中获取字段值（删除前的值）
					fieldValue := field.ReflectValueOf(tx.Statement.Context, tx.Statement.ReflectValue)
					if fieldValue.IsValid() && fieldValue.CanInterface() {
						change.OldValues[field.DBName] = fieldValue.Interface()

						// 如果是主键字段，设置记录ID
						if field.PrimaryKey {
							change.RecordID = fieldValue.Interface()
						}
					}
				}
			}
		}

		// 检查是否在事务中
		_, isInTransaction := tx.Statement.ConnPool.(interface{ Commit() error })

		if isInTransaction {
			// 在事务中，使用异步模式不进行wait
			err := c.processor.AddChange(change)
			if err != nil {
				fmt.Printf("处理变更时出错: %v\n", err)
			}
		} else {
			// 不在事务中，使用同步模式进行wait
			err := c.processor.AddChange(change)
			if err != nil {
				fmt.Printf("处理变更时出错: %v\n", err)
			}
			// 等待处理完成
			c.processor.Wait()
		}
	}
}

// HandleBeforeUpdate 处理更新操作前的增量计算并收集变更
func (c *ChangeHandler) HandleBeforeUpdate(tx *gorm.DB) {

	if tx.Statement != nil && tx.Statement.Model != nil {
		// 获取表名
		tableName := tx.Statement.Table
		if tableName == "" {
			return
		}

		// 获取模型名
		modelName := reflect.TypeOf(tx.Statement.Model).Elem().Name()

		// 创建变更记录
		change := &Change{
			ModelName: modelName,
			TableName: tableName,
			Type:      ChangeUpdate,
			OldValues: make(map[string]interface{}),
			NewValues: make(map[string]interface{}),
		}

		// 提取变更前的字段值
		if tx.Statement.Schema != nil {
			// 先获取主键值
			var pkField interface{} // 使用 interface{} 替代具体类型
			for _, field := range tx.Statement.Schema.Fields {
				if field.PrimaryKey {
					pkField = field
					pkValue := field.ReflectValueOf(tx.Statement.Context, tx.Statement.ReflectValue)
					if pkValue.IsValid() && pkValue.CanInterface() {
						change.RecordID = pkValue.Interface()
					}
					break
				}
			}

			// 如果有主键，则从数据库查询旧值
			if pkField != nil && change.RecordID != nil {
				// 使用反射获取DBName字段值
				pkFieldName := reflect.ValueOf(pkField).Elem().FieldByName("DBName").String()

				// 构建查询条件
				whereConditions := map[string]interface{}{pkFieldName: change.RecordID}

				// 创建一个临时实例来存储查询结果
				oldModel := reflect.New(tx.Statement.Schema.ModelType).Interface()

				// 从数据库查询当前记录
				result := tx.Session(&gorm.Session{}).Where(whereConditions).First(oldModel)
				if result.Error == nil {
					// 如果无法确定哪些字段发生了变化，则处理所有字段
					for _, field := range tx.Statement.Schema.Fields {
						if field.DBName != "" {
							// 获取旧值（从数据库查询结果中）
							oldFieldValue := field.ReflectValueOf(tx.Statement.Context, reflect.ValueOf(oldModel).Elem())
							// 获取新值（从当前模型中）
							newFieldValue := field.ReflectValueOf(tx.Statement.Context, tx.Statement.ReflectValue)
							if oldFieldValue.IsValid() && oldFieldValue.CanInterface() && newFieldValue.IsValid() && newFieldValue.CanInterface() && oldFieldValue.Interface() != newFieldValue.Interface() {
								change.OldValues[field.DBName] = oldFieldValue.Interface()
								change.NewValues[field.DBName] = newFieldValue.Interface()
							}
						}
					}
				}
			}
		}

		// 检查是否在事务中
		_, isInTransaction := tx.Statement.ConnPool.(interface{ Commit() error })

		if isInTransaction {
			// 在事务中，使用异步模式不进行wait
			err := c.processor.AddChange(change)
			if err != nil {
				fmt.Printf("处理变更时出错: %v\n", err)
			}
		} else {
			// 不在事务中，使用同步模式进行wait
			err := c.processor.AddChange(change)
			if err != nil {
				fmt.Printf("处理变更时出错: %v\n", err)
			}
			// 等待处理完成
			c.processor.Wait()
		}
	}
}
